package concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

/**
 * Created by admin on 2017/1/21.
 */
public class TestCyclicBarrier {

    static class Horse implements Runnable {
        private static int counter = 0;
        private final int id = counter++;
        private int strides = 0;
        private static Random random = new Random(47);
        private static CyclicBarrier barrier;

        public Horse(CyclicBarrier b) {
            barrier = b;
        }

        public synchronized int getStrides() {
            return strides;
        }

        @Override
        public void run() {
            try {
                while (!Thread.interrupted()) {
                    synchronized (this) {
                        strides += random.nextInt(3);
                    }
                    barrier.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
        @Override
        public String toString() {
            return "Horse{" +
                    "id=" + id + '}';
        }
        public String tracks(){
            StringBuilder s = new StringBuilder();
            for(int i = 0;i< getStrides();i++){
                s.append("*");
            }
            s.append(id);
            return s.toString();
        }
    }

    static class HorseRace{
        static final int FINISH_SIZE = 75;
        private List<Horse> horses = new ArrayList<>();
        private ExecutorService exec = Executors.newCachedThreadPool();
        private CyclicBarrier barrier;
        public HorseRace(int nHorses, final int pause){
            barrier = new CyclicBarrier(nHorses, () -> {
                StringBuilder s = new StringBuilder();
                for(int i = 0; i < FINISH_SIZE; i++){
                    s.append("=");
                }
                System.out.println(s);
                for(Horse horse : horses){
                    System.out.println(horse.tracks());
                }
                for(Horse horse : horses){
                    if(horse.getStrides() >= FINISH_SIZE){
                        System.out.println(horse + "won!");
                        exec.shutdownNow();
                        return;
                    }
                }
                try {
                    TimeUnit.MICROSECONDS.sleep(pause);
                } catch (InterruptedException e) {
                    System.out.print("barrier interrupted");
                }
            });
            for(int i = 0; i < nHorses;i++){
                Horse horse = new Horse(barrier);
                horses.add(horse);
                exec.execute(horse);
            }
        }
    }

    public static void main(String[] arag0){
        new HorseRace(7,200);
    }
}
